package logsink

import (
	"context"
	modeladmin "ia/common/model/admin"
	"ia/common/storage"
	"ia/common/support/global"
	"ia/common/support/tools"
	"time"

	"github.com/kataras/golog"
)

var (
	GLogSink       *LogSink
	GPolicyLogList []*modeladmin.AdminPolicy
)

type LogSink struct {
	logChan        chan *modeladmin.AdminLog
	autoCommitChan chan *LogBatch
}

type LogBatch struct {
	Logs []*modeladmin.AdminLog
}

func (logSink *LogSink) writeLoop() {
	var (
		log          *modeladmin.AdminLog
		logBatch     *LogBatch   // 当前的日志批次
		commitTimer  *time.Timer // 让这个批次超时自动提交
		timeoutBatch *LogBatch   // 超时批次
	)

	for {
		select {
		case log = <-logSink.logChan:
			if logBatch == nil {
				logBatch = &LogBatch{}
				commitTimer = time.AfterFunc(time.Duration(global.GConfig.App.Own.LogCommitTimeout)*time.Millisecond,
					// 如果并发调度情况下(两个协程操作了logBatch变量)，所以这儿只发出通知，不提交batch
					func(logBatch *LogBatch) func() {
						golog.Infof("logsink timer触发了%v", global.GConfig.App.Own.LogCommitTimeout)
						return func() {
							logSink.autoCommitChan <- logBatch
						}
					}(logBatch))
			}
			logBatch.Logs = append(logBatch.Logs, log)
			if len(logBatch.Logs) >= global.GConfig.App.Own.LogBatchSize {
				logSink.saveLogs(logBatch)
				logBatch = nil
				commitTimer.Stop() // 取消掉定时器
			}
		case timeoutBatch = <-logSink.autoCommitChan:
			// 判断过期批次仍旧是当前批次,防止重复提交日志批次
			if timeoutBatch == logBatch {
				logSink.saveLogs(timeoutBatch)
				logBatch = nil
			}
		}
	}
}

func (logSink *LogSink) saveLogs(batch *LogBatch) {
	// 调用三方接口会影响性能,放在这里处理
	for _, v := range batch.Logs {
		v.City = tools.NewClient(tools.Options{
			BaseURL: "http://whois.pconline.com.cn/ipJson.jsp",
		}).GetCityByIp(context.TODO(), v.City)
	}
	if err := storage.GDB1.CreateInBatches(&batch.Logs,
		global.GConfig.App.Own.LogBatchSize).Error; err != nil {
		golog.Errorf("批量保存操作日志错误:%v\n", err)
	}
}

func (logSink *LogSink) Flush() {
	golog.Error("iris admin 挂了，保存最后的admin log")
	// 	GLogSink.autoCommitChan
	// 	if err := storage.GDB1.CreateInBatches(&batch.Logs,
	// 		global.GConfig.App.Own.LogBatchSize).Error; err != nil {
	// 		golog.Errorf("批量保存操作日志错误:%v\n", err)
	// 	}
}

func (logSink *LogSink) Append(log *modeladmin.AdminLog) {
	select {
	case logSink.logChan <- log:
	default:
		// 队列满了就丢弃
	}
}

func InitLogSink() (err error) {
	var policyLogList = make([]*modeladmin.AdminPolicy, 0)
	if err := storage.GDB1.Find(&policyLogList, "logable=TRUE").Error; err != nil {
		golog.Error("初始化policy log 缓存失败,错误=%v", err)
	}
	GPolicyLogList = policyLogList

	GLogSink = &LogSink{
		logChan:        make(chan *modeladmin.AdminLog, 300),
		autoCommitChan: make(chan *LogBatch, 300),
	}
	go GLogSink.writeLoop()
	return
}
